import pandas as pd
import re
import numpy as np
from id_validator import validator

# 去除空值行
def remove_rows_with_null_values(data):
    # 检查每一行是否存在空值
    mask = data.isnull().any(axis=1)

    # 筛选出存在空值的行
    removed_rows = data[mask]

    # 删除存在空值的行，得到新的 DataFrame
    data.dropna(inplace = True)

    return removed_rows

def _checkId(idcard):
        '''
        idcard为身份证
        '''
        Errors = ['验证通过!', '身份证号码位数不对!', '身份证号码出生日期超出范围或含有非法字符!', '身份证号码校验错误!', '身份证地区非法!']
        idcard = str(idcard)
        idcard = idcard.strip()
        idcard_list = list(idcard)

        # 15位身份号码检测
        if len(idcard) == 15:
            # 闰年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))
            # 平年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))
            if ((int(idcard[6:8]) + 1900) % 4 == 0 or ((int(idcard[6:8]) + 1900) % 100 == 0 and (int(idcard[6:8]) + 1900) % 4 == 0)):
                ereg = re.compile(
                    '[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$')  # //测试出生日期的合法性
            else:
                ereg = re.compile(
                    '[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$')  # //测试出生日期的合法性
            if re.match(ereg, idcard):
                return True
            else:
                raise ValueError
            
            # 18位身份号码检测
        elif len(idcard) == 18:
                # 出生日期的合法性检查
            # 闰年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))
            # 平年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))
            if (int(idcard[6:10]) % 4 == 0 or (int(idcard[6:10]) % 100 == 0 and int(idcard[6:10]) % 4 == 0)):
                # 闰年出生日期的合法性正则表达式
                ereg = re.compile(
                    '[1-9][0-9]{5}[0-9]{4}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$')
            else:
                # 平年出生日期的合法性正则表达式
                ereg = re.compile(
                    '[1-9][0-9]{5}[0-9]{4}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$')
            # 测试出生日期的合法性
            if re.match(ereg, idcard):
                # 计算校验位
                S = (int(idcard_list[0]) + int(idcard_list[10])) * 7 + (int(idcard_list[1]) + int(idcard_list[11])) * 9 + (
                            int(idcard_list[2]) + int(idcard_list[12])) * 10 + (
                                int(idcard_list[3]) + int(idcard_list[13])) * 5 + (
                                int(idcard_list[4]) + int(idcard_list[14])) * 8 + (
                                int(idcard_list[5]) + int(idcard_list[15])) * 4 + (
                                int(idcard_list[6]) + int(idcard_list[16])) * 2 + int(idcard_list[7]) * 1 + int(
                    idcard_list[8]) * 6 + int(idcard_list[9]) * 3
                Y = S % 11
                M = "F"
                JYM = "10X98765432"
                M = JYM[Y]  # 判断校验位
                if M == idcard_list[17]:  # 检测ID的校验位
                    return True
                else:
                    raise ValueError
            else :
                raise ValueError
        else:
            raise ValueError


#身份证判断
def check_id(data,column_name):
    #创建新dataframe
    correct_ = pd.DataFrame()
    error_ = pd.DataFrame()
    for i,row in data.iterrows():
        idcard = row[column_name]
        try:
            _checkId(idcard)
        except:
            #添加到错误dataframe
            error_ = error_._append(row)
            continue
        #添加到正确dataframe
        correct_ = correct_._append(row)
    return correct_,error_


# # 身份证判断
# def check_id(data, column_name='客户编号'):
#     # 创建error dataframe
#     error_data = pd.DataFrame()
#     for index, row in data.iterrows():
#         customer_id = row[column_name]
#         # 判断客户编号是否符合条件
#         if validator.is_valid(customer_id) is False:
#             # 将不符合条件的行添加到新的 DataFrame
#             data.drop(index,inplace = True)
#             error_data = error_data._append(row)
#     return error_data

def judge_common_user(user_df, logistics_df,column_name='货主代码'):
    # 创建哈希表，将用户 dataframe 中的 id 字段存入哈希表
    user_ids = set(user_df['clientid'])

    # 创建空的正确数据和错误数据的列表
    correct_rows = []
    error_rows = []

    # 遍历物流 dataframe 的每一行
    for index, row in logistics_df.iterrows():
        # 检查 id 是否存在于哈希表中
        if row[column_name] in user_ids:
            # 如果存在，将该行数据添加到正确数据列表
            correct_rows.append(row)
        else:
            # 如果不存在，将该行数据添加到错误数据列表
            error_rows.append(row)

    # 根据正确数据和错误数据列表创建新的 dataframe
    correct_df = pd.DataFrame(correct_rows)
    error_df = pd.DataFrame(error_rows)

    # 返回正确数据和错误数据的 dataframe
    return correct_df, error_df

# # 物流信息中客户是否在客户信息表中
# def judge_common_user(data, user_data, wl_index=2, user_index=1):
#     '''
#     data为物流信息表;
#     user_data为用户信息表;
#     wl_index为物流表中用户身份证的列序列,默认是2;
#     user_index为用户表中用户身份证的列序列,默认是1;
#     前一个返回值是正确物流，后一个是错误物流
#     '''
#     # 创建新dataframe
#     correct_ = pd.DataFrame()
#     error_ = pd.DataFrame()
#     for i, txt in enumerate(data.values):
#         is_pass = False
#         idcard = txt[wl_index]
#         for user in user_data.values:
#             user_id = user[user_index]
#             if str(idcard) == str(user_id):
#                 # 添加到正确dataframe
#                 correct_ = correct_._append(data.iloc[i])
#                 is_pass = True
#                 # 本条物流信息判断结束
#                 break
#         if is_pass:
#             # 进入下一条
#             continue
#         # 添加到错误dataframe
#         error_ = error_._append(data.iloc[i])
#     return correct_, error_

# 修改
def amend(data, index_values):
    '''
    data为要修改的错误表
    index_values为字典类型，其中key为要修改的行列需要，value为需要重新写入的值
    举例如下：
    {'1,2':'none'}
    '''
    # 判断修改长度是否越界
    if len(data) < len(index_values):
        raise ValueError
    for i, j in index_values.items():
        try:
            # 分割行列值
            row, col = i.split(',')
            row = int(row)
            col = int(col)
            # 修改
            data.iloc[row, col] = j
        except:
            raise KeyError
    return data

# 异常值检测
def compare(data, index1=0, index2=None):
    '''
    比较判断，index1和index2为需要比较的两个列，index1<index2为正确，反之为错误
    若index2不传参数，则默认比较第一列是否非负
    '''
    correct_ = pd.DataFrame()
    error_ = pd.DataFrame()
    if index2 is not None:
        for i, txt in enumerate(data.values):
            if str(txt[index1]) > str(txt[index2]):
                error_ = error_.append(data.iloc[i])
            else:
                correct_ = correct_.append(data.iloc[i])
        return correct_, error_
    else:
        for i, txt in enumerate(data.values):
            if str(txt[index1]) < str(0):
                error_ = error_.append(data.iloc[i])
            else:
                correct_ = correct_.append(data.iloc[i])
        return correct_, error_

# 表连接
def merge_(data1, data2, data1_norm='', data2_norm=''):
    '''
    data1和data2为需要连接的两个表；
    data1_norm,data2_norm为连接两个表的考虑字段名，支持相等判断
    '''
    temporary = pd.merge(
        data1, data2, left_on=data1_norm, right_on=data2_norm)
    return temporary


# 表去重
def drop_duplicate(data, column_name):
    '''
    subset：表示要进去重的列名，默认为 None。
    keep：有三个可选参数，分别是 first、last、False;
    默认为 first，表示只保留第一次出现的重复项，删除其余重复项，last 表示只保留最后一次出现的重复项，False 则表示删除所有重复项。
    '''
    data.drop_duplicates(subset=column_name, keep ='first', inplace=True)
    return data

# 归一化
def normalization(data, col_name=''):
    '''
    data为传入表
    col_name为需要归一化的列字段名称
    '''
    def max_min_scaler(x): return (x - np.min(x)) / (np.max(x) - np.min(x))
    new_name = col_name+'_norm'
    data[new_name] = data[[col_name]].apply(max_min_scaler)
    return data

# 离散化
def discretizing(data, col_name, comparison_dic={}):
    '''
    data为传入表
    col_name为需要离散化的列字段序列
    comparison_dic为离散对照字典,举例如下:
    '''
    {'1': (-1, 'low'), '2': (2, 3), '3': (4, 'high')}
    list_ = []
    for n in range(len(data)):
        for k, (i, j) in comparison_dic.items():
            if i <= data.iloc[n, col_name] < j:
                data.iloc[n, col_name] = k
                continue
    return data

# 分组聚合
def grouping(data, column_name, column_name_value=''):
    if column_name_value == '':
        result = data[column_name].value_counts().reset_index()
        result.columns = [column_name, '数量']
        return result
    else:
        return data.groupby(column_name).get_group(column_name_value)
